import {
  CallHandler,
  ExecutionContext,
  HttpException,
  Injectable,
  NestInterceptor, UseGuards
} from "@nestjs/common";
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { Request } from 'express';
import { LogService } from '@/modules/log/log.service';
import { logDto } from '@/modules/log/dto/log.dto';
import { UAParser } from 'ua-parser-js';
import { CustomException } from "@/common/exceptions/custom.exception";

@Injectable()
export class UserLoggingInterceptor implements NestInterceptor {
  constructor(private readonly logService: LogService) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {

    const request = context.switchToHttp().getRequest<Request & { user: any }>();

    const newLogEntry = new logDto();
    newLogEntry.userId = request.user?.userId || request.user?.id || -1;
    newLogEntry.username = request.user?.username || "未知用户";

    // 分割 IPv6 地址
    let ip = request.ip || '未知IP';
    ip = ip.split('::ffff:')[1] || ip;
    newLogEntry.ip = ip;

    newLogEntry.method = request.method || '未知方法';
    newLogEntry.path = request.path || '未知路径';
    newLogEntry.errDetail = '';

    const userAgentString = request.headers['user-agent'];
    const parsedResult = new UAParser(userAgentString).getResult();

    // 获取设备信息
    const deviceInfo = parsedResult.device;
    const isMobile = deviceInfo.type === 'mobile' ? 1 : 0;
    const isWechat = userAgentString.match(/MicroMessenger/i) ? 1 : 0;
    newLogEntry.device = isMobile ? (isWechat ? '微信' : '移动端') : 'PC端';

    // 获取操作系统信息
    const osInfo = parsedResult.os;
    newLogEntry.os =
      osInfo.name && osInfo.version ? osInfo.name + ' ' + osInfo.version : '未知操作系统';

    // 获取浏览器信息
    const browserInfo = parsedResult.browser;
    newLogEntry.browser =
      browserInfo.name && browserInfo.version
        ? browserInfo.name + ' ' + browserInfo.version
        : '未知浏览器';

    return next.handle().pipe(
      tap({
        next: async () => {
          newLogEntry.status = context.switchToHttp().getResponse().statusCode;
          await this.logService.createLog(newLogEntry);
        },
        error: async (err) => {
          newLogEntry.status = this.getCodeFromException(err);
          newLogEntry.errDetail = err.stack || err.message;
          await this.logService.createLog(newLogEntry);
        },
      }),
    );
  }

  private getCodeFromException(err: any): number {
    if (err instanceof CustomException) {
      return err.getCode();
    } else {
      return err instanceof HttpException ? err.getStatus() : 500;
    }
  }
}